float4x4 WorldViewProjection;
float4x4 World;
float3 CameraPosition;
float3 LightDir;
float HeightScale;

// Structs
struct VS_INPUT
{
    float4 position				: POSITION;
	float3 normal				: NORMAL;
	float2 uv					: TEXCOORD0;
	float3 tangent				: TANGENT0;
};

struct VS_OUTPUT
{
    float4 position          : POSITION;
	float3 positionWS :TEXCOORD6;
    float2 uv				 : TEXCOORD0;
    float3 vLightTS          : TEXCOORD1;   // light vector in tangent space, denormalized
    float3 vViewTS           : TEXCOORD2;   // view vector in tangent space, denormalized
    float2 vParallaxOffsetTS : TEXCOORD3;   // Parallax offset vector in tangent space
    float3 vNormalWS         : TEXCOORD4;   // Normal vector in world space
    float3 vViewWS           : TEXCOORD5;   // View vector in world space
	float3 tangentWS         :COLOR0;
	float3 binormalWS		:COLOR1;	
    
}; 

// Shaders
VS_OUTPUT main(VS_INPUT In)
{
   VS_OUTPUT Out;
        
    // Transform and output input position 
    Out.position = mul( In.position, WorldViewProjection );
       
    // Propagate texture coordinate through:
    Out.uv = In.uv;

	float3 binormal = cross(In.tangent, In.normal);
    // Transform the normal, tangent and binormal vectors from object space to homogeneous projection space:
    float3 vNormalWS   = mul( In.normal,   (float3x3) World );
    float3 vTangentWS  = mul( In.tangent,  (float3x3) World );
	float3 vBinormalWS = mul(binormal, (float3x3) World );
    Out.tangentWS = vTangentWS;
	Out.binormalWS = vBinormalWS;
    // Propagate the world space vertex normal through:   
    Out.vNormalWS = vNormalWS;
    
    vNormalWS   = normalize( vNormalWS );
    vTangentWS  = normalize( vTangentWS );
    vBinormalWS = normalize( vBinormalWS );
    
    // Compute position in world space:
    float4 vPositionWS = mul( In.position, World );

	Out.positionWS = vPositionWS.rgb;
                 
    // Compute and output the world view vector (unnormalized):
    float3 vViewWS = CameraPosition - vPositionWS.xyz;
    Out.vViewWS = vViewWS;

    // Compute denormalized light vector in world space:
    float3 vLightWS = LightDir;
       
    // Normalize the light and view vectors and transform it to the tangent space:
    float3x3 mWorldToTangent = float3x3( vTangentWS, vBinormalWS, vNormalWS );
       
    // Propagate the view and the light vectors (in tangent space):
    Out.vLightTS = mul( vLightWS, mWorldToTangent );
    Out.vViewTS  = mul( mWorldToTangent, vViewWS  );
       
    // Compute the ray direction for intersecting the height field profile with 
    // current view ray. See the above paper for derivation of this computation.
         
    // Compute initial parallax displacement direction:
    float2 vParallaxDirection = normalize(  Out.vViewTS.xy );
       
    // The length of this vector determines the furthest amount of displacement:
    float fLength         = length( Out.vViewTS );
    float fParallaxLength = sqrt( fLength * fLength - Out.vViewTS.z * Out.vViewTS.z ) / Out.vViewTS.z; 
       
    // Compute the actual reverse parallax displacement vector:
    Out.vParallaxOffsetTS = vParallaxDirection * fParallaxLength;
       
    // Need to scale the amount of displacement to account for different height ranges
    // in height maps. This is controlled by an artist-editable parameter:
    Out.vParallaxOffsetTS *= HeightScale;

   return Out;
}
